package gamemodel;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.util.Observable;
import java.util.Observer;

import com.google.gson.Gson;

public class Player implements Observer, Collidable{

	private transient Ball ball ;
	private Coordinate position; 
	private transient Vector2d velocity; 
	private transient int exp; //exponential decay value to create slow down affect
	private String name;
	private int team; 
	
	public static final float RADIUS = 16; //needed to make public for game model to set coordinates when adding player
	private static final float MASS = 4; 
	private static final int MAX_VELOCITY = 3; 
	private static final int DEFAULT_EXPONENT = 0; 
	private static final double DEFAULT_BASE = 0.9; 
	
	public Player(String name, float x, float y, int team){
		this.name = name;
		this.team = team; 
		this.position = new Coordinate(x,y); 
		this.velocity = new Vector2d(0, 0); 
	}
	
	public int getTeam(){
		return this.team; 
	}
	
	public void setTeam(int team){
		//error check to see if its same value
		if (this.team == team){
			return; 
		}
		
		//error check that team is a valid identity 
		if (team != ScoreBoard.TEAM_A && team != ScoreBoard.TEAM_B && team != ScoreBoard.TEAM_SPECTATOR){
			return; 
		}
		
		this.team = team; 
		
	}
	
	public void setPosition(float x, float y){
		this.position.set(x, y); 
	}
	
	public void setVelocity(float x, float y){
		this.velocity.set(x, y); 
	}
	
	public String getName(){
		return this.name; 
	}
	
	@Override
	public void update(Observable object, Object arg) {
		this.ball = (Ball) object; 
		//System.out.println(this.name + " has been updated! - Position:" + ballPosition);
	} 
	
	@Override
	public float getRadius() {
		return Player.RADIUS; 
	}

	/**
	 * Returns a copy of the actual position coordinates
	 */
	@Override
	public Coordinate getPosition() {
		return this.position; 
	}

	@Override
	public float getMass() {
		return Player.MASS; 
	}

	@Override
	public void setPosition(Vector2d v) {
		this.position.set(v.getX(), v.getY()); 
	}

	@Override
	public Vector2d getVelocity() {
		return this.velocity; 
	}
	
	@Override
	public void setVelocity(Vector2d v){
		this.velocity = v; 
	}
	
	public void performMove(float dx, float dy){		
		float vx; 
		float vy; 
		
		//player has not moved, so create slow down affect
		if (dx == 0 && dy == 0){
			vx = this.velocity.getX() * (float) Math.pow(DEFAULT_BASE, exp - 15) ;
			vy = this.velocity.getY() * (float) Math.pow(DEFAULT_BASE, exp - 15) ;
			this.exp++; 
		} else {
			vx = dx;
			vy = dy ;
			this.exp = DEFAULT_EXPONENT; 
		}
		
		//set a max limit on what the velocity could be
		if (vx > MAX_VELOCITY){
			vx = MAX_VELOCITY; 
		} else if (vx < -1 * MAX_VELOCITY){
			vx = -1 * MAX_VELOCITY; 
		}
		if (vy > MAX_VELOCITY){
			vy = MAX_VELOCITY; 
		} else if (vy < -1 * MAX_VELOCITY){
			vy = -1 * MAX_VELOCITY; 
		}
		
		position.translate(dx + vx, dy + vy); 
		this.velocity.set(vx, vy); 
		if (TestConstant.DEBUG) System.out.println("name: " + this.name + " x:" + this.getPosition().getX() + " y:" + this.getPosition().getY() + " vx:"+ this.velocity.getX() + " vy: " + this.velocity.getY() + " dx:" + dx + " dy:" + dy); 
	}
	
	public void performKick(){
		if (GameModel.isColliding(this, ball)){
			this.ball.resetExponent() ; 
			this.kick(); 
		}
	}
	
	private void kick(){
		//gets the minimum translation distance after intersection
		Vector2d delta = this.getPosition().subtract(this.ball.getPosition()); 
		float d = delta.getLength(); 
		Vector2d mtd = delta.multiply(((this.getRadius() + this.ball.getRadius())-d)/d);
		
		//resolve intersection -- inverse mass quantities
		float im1 = 1/this.getMass(); 
		float im2 = 1/this.ball.getMass(); 
		
		//push-pull them based on their mass 
		//this.setPosition(this.getPosition().add(mtd.multiply(im1 / (im1 + im2))));
	    this.ball.setPosition(this.ball.getPosition().subtract(mtd.multiply(im2 / (im1 + im2))));
	    
	    //impact speed 
	    Vector2d v = (this.getVelocity().subtract(this.ball.getVelocity()));
	    float vn = v.dot(mtd.normalize());
	    
	    // sphere intersecting but moving away from each other already
	    if (vn > 0.0f) return;

	    // collision impulse
	    float i = (-(1.0f + Collidable.restitution) * vn) / (im1 + im2);
	    Vector2d impulse = mtd.multiply(i*50);
	    
	    // change in momentum		
	    //o1.setVelocity(o1.getVelocity().add(impulse.multiply(im1)));
	    this.ball.setVelocity(this.ball.getVelocity().subtract(impulse.multiply(im2)));
	}

	public void paint(Graphics2D g){
		g.setColor(Color.BLUE); 
		Ellipse2D.Double circle = new Ellipse2D.Double(this.position.getX() - Player.RADIUS, this.position.getY() - Player.RADIUS, Player.RADIUS * 2, Player.RADIUS * 2); 
		g.fill(circle); 		
	}
}
